package com.coai.warehouse.service

import com.coai.common.exception.ResourceNotFoundException
import com.coai.common.exception.ValidationException
import com.coai.warehouse.model.*
import com.coai.warehouse.repository.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.springframework.data.domain.PageRequest
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.awaitBody
import java.time.LocalDateTime

/**
 * 智能仓储服务
 */
/**
 * 智能仓储服务
 * 
 * 提供仓储管理的核心功能，包括：
 * - AI智能选址推荐
 * - 拣货路径优化（TSP算法）
 * - AI质量检测
 * - 库存预警分析
 * - 入库/出库单管理
 * 
 * @property warehouseRepository 仓库仓储
 * @property locationRepository 库位仓储
 * @property inventoryRepository 库存仓储
 * @property inboundOrderRepository 入库单仓储
 * @property outboundOrderRepository 出库单仓储
 * @property eventService 事件发布服务
 */
@Service
class WarehouseService(
    private val warehouseRepository: WarehouseRepository,
    private val locationRepository: WarehouseLocationRepository,
    private val inventoryRepository: InventoryRepository,
    private val inboundOrderRepository: InboundOrderRepository,
    private val inboundItemRepository: InboundItemRepository,
    private val outboundOrderRepository: OutboundOrderRepository,
    private val outboundItemRepository: OutboundItemRepository,
    private val warehouseEventService: WarehouseEventService,
    private val webClient: WebClient
) {
    
    /**
     * AI智能选址推荐
     */
    /**
     * AI智能选址推荐
     * 
     * 基于多维度因素为商品推荐最优库位：
     * - 库位容量匹配
     * - 商品类型匹配
     * - 历史存储数据
     * - 库位使用频率
     * 
     * @param warehouseId 仓库ID
     * @param productId 商品ID
     * @param quantity 数量
     * @param requiredCapacity 所需容量
     * @return 推荐的最优库位
     */
    suspend fun recommendLocation(
        warehouseId: String,
        productId: String,
        quantity: Int,
        requiredCapacity: Double
    ): WarehouseLocation = withContext(Dispatchers.IO) {
        
        // 1. 获取可用库位
        val availableLocations = locationRepository.findAvailableLocations(
            warehouseId, requiredCapacity, PageRequest.of(0, 10)
        )
        
        if (availableLocations.isEmpty()) {
            throw ValidationException("没有可用库位")
        }
        
        // 2. 调用AI服务计算推荐度
        val locationScores = calculateLocationScores(
            warehouseId, productId, availableLocations
        )
        
        // 3. 更新推荐度评分
        locationScores.forEach { (locationId, score) ->
            val location = availableLocations.find { it.id == locationId }
            location?.let {
                it.recommendScore = score
                locationRepository.save(it)
            }
        }
        
        // 4. 返回最佳库位
        availableLocations.maxByOrNull { it.recommendScore ?: 0.0 }
            ?: throw ValidationException("无法推荐库位")
    }
    
    /**
     * 计算库位推荐度（调用AI服务）
     */
    private suspend fun calculateLocationScores(
        warehouseId: String,
        productId: String,
        locations: List<WarehouseLocation>
    ): Map<String, Double> {
        
        // TODO: 实际应调用AI服务
        // 考虑因素：
        // 1. 产品特性（重量、尺寸、易碎性）
        // 2. 库位特性（高度、承重、温度）
        // 3. 历史数据（周转率、拣货频率）
        // 4. 就近原则（减少移动距离）
        
        return locations.associate { 
            it.id!! to (0.5 + Math.random() * 0.5) // 模拟评分 0.5-1.0
        }
    }
    
    /**
     * AI优化拣货路径
     */
    suspend fun optimizePickingPath(orderId: String): PickingPathResult = withContext(Dispatchers.IO) {
        
        val order = outboundOrderRepository.findById(orderId)
            .orElseThrow { ResourceNotFoundException("出库单不存在") }
        
        val items = outboundItemRepository.findByOrderId(orderId)
        
        // 1. 为每个明细分配库存
        val allocations = items.map { item ->
            val inventory = allocateInventory(item.productId, item.requiredQuantity)
            item.inventoryId = inventory.id
            inboundItemRepository.save(item)
            
            LocationInfo(
                locationId = inventory.locationId,
                productId = item.productId,
                quantity = item.requiredQuantity
            )
        }
        
        // 2. 调用AI优化拣货路径
        val optimizedPath = calculateOptimalPath(order.warehouseId, allocations)
        
        // 3. 更新拣货顺序
        optimizedPath.forEachIndexed { index, locationId ->
            val item = items.find { 
                val inv = inventoryRepository.findById(it.inventoryId!!).orElse(null)
                inv?.locationId == locationId
            }
            item?.let {
                it.pickingSequence = index + 1
                outboundItemRepository.save(it)
            }
        }
        
        // 4. 保存路径到订单
        order.pickingPath = optimizedPath.joinToString(",")
        outboundOrderRepository.save(order)
        
        PickingPathResult(
            path = optimizedPath,
            estimatedDistance = calculateDistance(optimizedPath),
            estimatedTime = calculateTime(optimizedPath)
        )
    }
    
    /**
     * 计算最优拣货路径（调用AI服务）
     */
    private suspend fun calculateOptimalPath(
        warehouseId: String,
        allocations: List<LocationInfo>
    ): List<String> {
        
        // TODO: 实际应调用AI服务
        // 使用TSP（旅行商问题）算法优化路径
        // 考虑：距离、优先级、批次处理
        
        // 简化版：按库位编码排序
        return allocations.map { it.locationId }.distinct().sorted()
    }
    
    /**
     * AI质量检测
     */
    /**
     * AI质量检测
     * 
     * 使用图像识别技术自动检测商品质量
     * 
     * @param itemId 商品项ID
     * @param imageData 商品图片数据
     * @return 质检结果
     */
    suspend fun performAIQualityCheck(
        itemId: String,
        imageData: ByteArray
    ): QualityCheckResult = withContext(Dispatchers.IO) {
        
        val item = inboundItemRepository.findById(itemId)
            .orElseThrow { ResourceNotFoundException("入库明细不存在") }
        
        // 调用AI服务进行图像质检
        val qcResult = callAIQualityCheck(imageData)
        
        // 更新质检结果
        item.qcStatus = if (qcResult.passed) QCStatus.PASSED else QCStatus.FAILED
        item.aiQcResult = qcResult.toJson()
        inboundItemRepository.save(item)
        
        // 发布事件
        warehouseEventService.publishQualityCheckCompleted(item, qcResult)
        
        qcResult
    }
    
    /**
     * 调用AI质检服务
     */
    private suspend fun callAIQualityCheck(imageData: ByteArray): QualityCheckResult {
        // TODO: 实际调用AI服务
        // 检测：外观缺陷、尺寸偏差、标签识别
        
        return QualityCheckResult(
            passed = true,
            score = 0.95,
            defects = emptyList(),
            confidence = 0.98
        )
    }
    
    /**
     * 库存预警分析
     */
    suspend fun analyzeInventoryAlerts(warehouseId: String): List<InventoryAlert> = withContext(Dispatchers.IO) {
        
        val inventories = inventoryRepository.findByWarehouseId(warehouseId)
        val alerts = mutableListOf<InventoryAlert>()
        
        inventories.forEach { inventory ->
            // 1. 库存不足预警
            if (inventory.availableQuantity < 10) { // 简化阈值
                alerts.add(InventoryAlert(
                    type = AlertType.LOW_STOCK,
                    productId = inventory.productId,
                    currentQuantity = inventory.quantity,
                    message = "库存不足，当前可用：${inventory.availableQuantity}"
                ))
            }
            
            // 2. 即将过期预警
            inventory.expiryDate?.let { expiryDate ->
                if (expiryDate.isBefore(LocalDateTime.now().plusDays(30))) {
                    alerts.add(InventoryAlert(
                        type = AlertType.EXPIRING,
                        productId = inventory.productId,
                        currentQuantity = inventory.quantity,
                        message = "即将过期：${expiryDate}"
                    ))
                }
            }
        }
        
        alerts
    }
    
    /**
     * 创建入库单
     */
    @Transactional
    fun createInboundOrder(
        warehouseId: String,
        supplierId: String,
        type: InboundType,
        items: List<InboundItemRequest>,
        plannedTime: LocalDateTime
    ): InboundOrder {
        
        val orderNo = generateOrderNo("IN")
        
        val order = InboundOrder(
            orderNo = orderNo,
            warehouseId = warehouseId,
            supplierId = supplierId,
            type = type,
            plannedTime = plannedTime
        )
        
        val savedOrder = inboundOrderRepository.save(order)
        
        // 创建明细
        items.forEach { itemReq ->
            val item = InboundItem(
                orderId = savedOrder.id!!,
                productId = itemReq.productId,
                plannedQuantity = itemReq.quantity
            )
            inboundItemRepository.save(item)
        }
        
        // 发布事件
        warehouseEventService.publishInboundOrderCreated(savedOrder)
        
        return savedOrder
    }
    
    /**
     * 创建出库单
     */
    @Transactional
    fun createOutboundOrder(
        warehouseId: String,
        customerId: String,
        type: OutboundType,
        items: List<OutboundItemRequest>,
        priority: Priority,
        plannedTime: LocalDateTime
    ): OutboundOrder {
        
        val orderNo = generateOrderNo("OUT")
        
        val order = OutboundOrder(
            orderNo = orderNo,
            warehouseId = warehouseId,
            customerId = customerId,
            type = type,
            priority = priority,
            plannedTime = plannedTime
        )
        
        val savedOrder = outboundOrderRepository.save(order)
        
        // 创建明细
        items.forEach { itemReq ->
            val item = OutboundItem(
                orderId = savedOrder.id!!,
                productId = itemReq.productId,
                requiredQuantity = itemReq.quantity
            )
            outboundItemRepository.save(item)
        }
        
        // 发布事件
        warehouseEventService.publishOutboundOrderCreated(savedOrder)
        
        return savedOrder
    }
    
    // 辅助方法
    
    private fun allocateInventory(productId: String, quantity: Int): Inventory {
        val inventories = inventoryRepository.findAvailableInventory(
            productId, quantity, PageRequest.of(0, 1)
        )
        
        return inventories.firstOrNull() 
            ?: throw ValidationException("库存不足：产品$productId")
    }
    
    private fun calculateDistance(path: List<String>): Double {
        // TODO: 计算实际距离
        return path.size * 10.0 // 简化
    }
    
    private fun calculateTime(path: List<String>): Int {
        // TODO: 计算实际时间（秒）
        return path.size * 60 // 简化
    }
    
    private fun generateOrderNo(prefix: String): String {
        val timestamp = System.currentTimeMillis()
        return "$prefix${timestamp}"
    }
}

// DTOs
data class LocationInfo(
    val locationId: String,
    val productId: String,
    val quantity: Int
)

data class PickingPathResult(
    val path: List<String>,
    val estimatedDistance: Double,
    val estimatedTime: Int
)

data class QualityCheckResult(
    val passed: Boolean,
    val score: Double,
    val defects: List<String>,
    val confidence: Double
) {
    fun toJson(): String {
        return """{"passed":$passed,"score":$score,"defects":${defects},"confidence":$confidence}"""
    }
}

data class InventoryAlert(
    val type: AlertType,
    val productId: String,
    val currentQuantity: Int,
    val message: String
)

enum class AlertType {
    LOW_STOCK,
    EXPIRING,
    DAMAGED
}

data class InboundItemRequest(
    val productId: String,
    val quantity: Int
)

data class OutboundItemRequest(
    val productId: String,
    val quantity: Int
)
